package server;

import java.io.Serializable;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Iterator;

import javax.swing.JTextArea;
import abstractions.*;

public class ServerServicesStub extends UnicastRemoteObject  implements ServerServices{
	
	//foi retirado o static
	public HashMap<Integer, ClientServices> clientList = new HashMap<Integer, ClientServices>();
	boolean login;
	private JTextArea log;
	private OpenDoc op;
	
	public LinkedList<CommandC> lista1 = new LinkedList<CommandC>();
	public LinkedList<CommandC> lista2 = new LinkedList<CommandC>();
	
	protected ServerServicesStub(JTextArea l) throws RemoteException {
		// construtor CommandC(int uid, int docId, PosC pos, Part out, Part in)
		// construtor PosC(AtomId aid, int c)
		// construtor public AtomId(ArrayList<Integer> id)
		super();
		log = l;
		login = false;
		// Gerando a lista1
		// supostamente, necessita dos locks 1 e 2 - o 3 esta ai apenas para dar erro
		// testes de locks sem alteracao no texto
		
		lista1.add(new CommandC(1 , 1 , new PosC(new AtomId(new ArrayList<Integer>(1)),0) , new Part("") , new Part("")));
		lista1.add(new CommandC(1 , 1 , new PosC(new AtomId(new ArrayList<Integer>(2)),0) , new Part("") , new Part("")));
		lista1.add(new CommandC(1 , 1 , new PosC(new AtomId(new ArrayList<Integer>(3)),0) , new Part("") , new Part("")));
		// trocando os dois primeiros versos de lugar
		lista1.add(new CommandC(1 , 1 , new PosC(new AtomId(new ArrayList<Integer>(1)),0) , new Part("Minhas duvidas sao incertas") , new Part("Minhas certezas duvidosas")));
		lista1.add(new CommandC(1 , 1 , new PosC(new AtomId(new ArrayList<Integer>(1)),0) , new Part("Minhas certezas duvidosas") , new Part("Minhas duvidas sao incertas")));
	}
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public int login(ClientServices cl, int clientId, String logname, String password)
			throws RemoteException {
		
		log.append("login ("+clientId + " , " + logname + " , "+ password + ")\n");
		if (logname.equals("rog") && password.equals("rog") && !login)
		{ 
			log.append("-----Login com sucesso\n");
			clientList.put(clientId, cl);
			login = true;
			LoggedUser l = new LoggedUser(1, logname, password, "you", "email@email");	
			return 1;
		}
		return -1;
	}

	public boolean logout(int clientId, int userId) throws RemoteException {
		log.append("logout ("+clientId + " , " + userId + ")\n");
		if (login)
		{			
			log.append("------Logout com sucesso\n");
			login = false;
			return true;
		}
		log.append("------Logout com erro\n");
		return false;
	}

	public OpenDocInterface docOpen(int clientId, int userId, String docPath)
			throws RemoteException {

		log.append("docOpen("+clientId+","+userId+","+docPath+")\n");
		if ( docPath.equals("initDocInput.txt"))
		{	
			if (op == null)
			{
				log.append("------docOpen com erro - documento nao adicionado\n");
				return null;
			}
			else
			{
				op.editedBy.add(1);
				op.editedBy.add(2);
				op.editedBy.add(3);
				op.editedBy.add(4);
				op.locked.put(new AtomId(new ArrayList<Integer>(3)), 4);
				op.locked.put(new AtomId(new ArrayList<Integer>(6)), 3);
				op.locked.put(new AtomId(new ArrayList<Integer>(9)), 2);				
				
			}
			log.append("------docOpen com sucesso\n");
		}
		else
		{
			log.append("------docOpen com erro - documento nao existe\n");
			return null;
		}
		return op;
	}

	public void docClose(int clientId, int userId, int docId)
			throws RemoteException {
		
		log.append("docClose("+clientId+","+userId+","+docId+")\n");
		if (op != null )
			op.editedBy.remove(1);
		else
		{
			log.append("-----Documento nao aberto\n");
			return;
		}
		log.append("-----Documento fechado com sucesso\n");
	}

	public boolean lockRequest(int clientId, int userId, int docId, AtomId aId)
			throws RemoteException {

		log.append("lockRequest("+clientId+","+userId+","+docId+","+aId.id+")\n");
		if (op != null )
			op.locked.put(aId, userId);	
		else
		{
			log.append("-----Erro LockRequest documento nao esta aberto\n");
			return false;
		}		
			
		log.append("-----LockRequest com sucesso\n");
		return true;
	}

	public boolean lockRelease(int clientId, int userId, int docId, AtomId aId)
			throws RemoteException {

		log.append("lockRelease("+clientId+","+userId+","+docId+","+aId.id+")\n");
		if (op != null )
			if (op.locked.containsKey(aId))			
				op.locked.remove(aId);	
			else
			{
				log.append("-----Erro LockRelease nao ha lock\n");
				return false;
			}
		else
		{
			log.append("-----Erro LockRelease documento nao esta aberto\n");
			return false;
		}
		log.append("------LockRelease com sucesso\n");
		return true;
	}

	public boolean updateDoc(int clientId, int userId, int docId,
			LinkedList<CommandC> cmds) throws RemoteException {
		// Se algum CommandC da lista for invalido, nenhum pode ser processado
			Iterator itr = cmds.iterator();
			CommandC cmd;
			while (itr.hasNext()){
				cmd = (CommandC) itr.next();
				if (userId != cmd.uid){
					log.append("Nao se pode enviar updates em nome de outros usuarios\n");
					return false;
				}
				if (docId != cmd.docId){
					log.append("Conflito entre o enderecamento dos docs\n");
					return false;
				}
				if (!op.editedBy.contains(userId)){
					log.append("Usuario nao tem esta com o doumento aberto\n");
					return false;
				}
				int lockpair = op.locked.get(cmd.pos.aid); //lockpair eh o UserID dono do lock do atomo
				if (lockpair != userId){
					log.append("Usuario nao possui o lock necessario\n");
					return false;
				}
			}
			itr = cmds.iterator();
			int i,j;
			String conteudo, orig;
			while (itr.hasNext()){
				cmd = (CommandC) itr.next();
				orig = op.atomizer.get(cmd.pos.aid).getString(); // conteudo original do atomo
				i = op.al.indexOf(op.atomizer.get(cmd.pos.aid)); // indice do atomo na lista ligada (al) do doc (op)
				j = cmd.pos.getC(); // offset dentro do atomo
				// pode fazer um teste de verificacao se o OUT existe e esta no lugar correto...
				String in = cmd.in.toString();
				int size = cmd.out.toString().length();
				conteudo = orig.substring(0,j) + in + orig.substring(j+size);
				op.al.get(i).setString(conteudo);
			}
			return true;
	}


	public boolean docRemove(int clientId, int userId, String docName)
			throws RemoteException {

		log.append("DocRemove("+clientId+","+userId+","+docName+")\n");
		if (op == null)
		{
			log.append("------docRemove erro - documento nao criado\n");
			return false;
		}
		op = null;
		log.append("------docRemove com sucesso\n");
		return true;
	}

	public boolean docAdd(int clientId, int userId, String docName,
			String docText) throws RemoteException {
		
		log.append("DocAdd("+clientId+","+userId+","+docName+","+docText+")\n");
		if (docName.equals("initDocInput.txt") && docText.equals("Minhas duvidas sao incertas\nMinhas certezas duvidosas\nMinhas contradicoes se confirmam\n"+
                "Meu lirismo e unissono\nMinha vontade ociosa\nMeu romantismo carnal\nMinha filosofia e plana\n"+
                "Minha bondade tem gana\nMinha calma e letal\n"))
		{	
			if (op == null)
				op = new OpenDoc(new Doc(docName, " ", true), docText);			
		}
		else
		{
			log.append("-------docAdd errado\n");
			return false;
		}
		log.append("-----docAdd com sucesso\n");
		return true;
	};
}